#--code:utf-8 -----
from flask import Flask, render_template, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import json
import requests
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger

app = Flask(__name__)

# 配置SQLite数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///CP.db'

# 创建数据库对象
db = SQLAlchemy(app)

# 创建一个后台调度器
scheduler = BackgroundScheduler()

# 配置调度器在应用启动时启动
scheduler.start()

# 定义中奖数字表结构
class Numbers(db.Model):
    # id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    lotteryDrawNum = db.Column(db.String(80), unique=True, nullable=False, primary_key=True)  # 期号
    type = db.Column(db.Integer, nullable=False)  # 类型：1、大乐透；2、双色球；
    draw_date = db.Column(db.String(10), nullable=False)  # 开奖日期
    parity_ratio = db.Column(db.String(10), nullable=True)  # 奇偶比
    Interval_ratio = db.Column(db.String(10), nullable=True) # 区间比
    f_1 = db.Column(db.Integer, nullable=True)  # 前区
    f_2 = db.Column(db.Integer, nullable=True)
    f_3 = db.Column(db.Integer, nullable=True)
    f_4 = db.Column(db.Integer, nullable=True)
    f_5 = db.Column(db.Integer, nullable=True)
    f_6 = db.Column(db.Integer, nullable=True)
    l_1 = db.Column(db.Integer, nullable=True)  # 后区
    l_2 = db.Column(db.Integer, nullable=True)


# 数字属性表结构
class NumbersAttribute(db.Model):
    lotteryDrawNum = db.Column(db.String(80), unique=True, nullable=False, primary_key=True)  # 期号
    number_id = db.Column(db.Integer)  # 号码
    thermal_value = db.Column(db.Integer, nullable=True)  # 冷热程度
    freq = db.Column(db.Float, nullable=True)  # 出现的频率
    prediction_coefficient = db.Column(db.Integer, nullable=True)  # 预测出现的权重

# 预测表结构
class PredictionNumbers(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    lotteryDrawNum = db.Column(db.String(80), unique=True, nullable=False)  # 期号
    prediction_number = db.Column(db.String(80), unique=True, nullable=False)  # 预测号


def double_chromosphere_winning_rule(f_cnt=0, l_cnt=0):
    # 双色球中奖规则, 前区中奖数， 后区中奖数
    if f_cnt == 6 and l_cnt == 1:
        return 1
    elif f_cnt == 6 and l_cnt == 0:
        return 2
    elif f_cnt == 5 and l_cnt == 1:
        return 3
    elif f_cnt == 5 and l_cnt == 0:
        return 4
    elif f_cnt == 4 and l_cnt == 1:
        return 4
    elif f_cnt == 4 and l_cnt == 0:
        return 5
    elif f_cnt == 3 and l_cnt == 1:
        return 5
    elif f_cnt < 3 and l_cnt == 1:
        return 6
    else:
        return 0

def lottery_winning_rule(f_cnt=0, l_cnt=0):
    # 大乐透中奖规则, 前区中奖数， 后区中奖数
    if f_cnt == 5 and l_cnt == 2:
        return 1
    elif f_cnt == 5 and l_cnt == 1:
        return 2
    elif f_cnt == 5 and l_cnt == 0:
        return 3
    elif f_cnt == 4 and l_cnt == 2:
        return 4
    elif f_cnt == 4 and l_cnt == 1:
        return 5
    elif f_cnt == 3 and l_cnt == 2:
        return 6
    elif f_cnt == 4 and l_cnt == 0:
        return 7
    elif f_cnt == 3 and l_cnt == 1:
        return 8
    elif f_cnt == 2 and l_cnt == 2:
        return 8
    elif f_cnt == 3 and l_cnt == 0:
        return 9
    elif f_cnt == 1 and l_cnt == 2:
        return 9
    elif f_cnt == 2 and l_cnt == 1:
        return 9
    elif f_cnt == 0 and l_cnt == 2:
        return 9
    else:
        return 0


def is_winning(numbers, lottery_type, issue_number):
    # 中奖信息查询
    # 传入的信息包括：期号，号码（列表），彩票类型（1:大乐透，2：双色球）
    if not numbers:
        return None
    with app.app_context():
        win_number = Numbers.query.filter_by(lotteryDrawNum = issue_number, type = lottery_type).first()
        if lottery_type == 1:
            # 大乐透前区5个，后续2个
            win_f = [win_number.f_1,win_number.f_2,win_number.f_3,win_number.f_4,
                     win_number.f_5]
            win_l = [win_number.l_1, win_number.l_2]
            number_f = numbers[0:5]
            number_l = numbers[5:8]
        else:
            # 双色球前区6个，后续1个
            win_f = [win_number.f_1, win_number.f_2, win_number.f_3, win_number.f_4,
                     win_number.f_5,win_number.f_6]
            win_l = [win_number.l_1]
            number_f = numbers[0:6]
            number_l = numbers[6:7]
        # 分区逐个检查
        f_cnt = 0  # 前区中间号码数
        l_cnt = 0  # 后区中间号码数
        for k in number_f:
            if k in win_f:
                f_cnt += 1
        for j in number_l:
            if j in win_l:
                l_cnt += 1
        # print(number_f, number_l)
        # print("中奖号码：",win_f, win_l)
        # print("中了几个：", f_cnt, l_cnt)
        if lottery_type == 1:
            hit_in = lottery_winning_rule(f_cnt, l_cnt)
        else:
            hit_in =  double_chromosphere_winning_rule(f_cnt, l_cnt)

        return {"win": hit_in, "draw_date": win_number.draw_date, "win_number":win_f + win_l}

@app.route('/')
def index():
    issue_numbers= [""]

    return render_template('index.html', issue_numbers=issue_numbers)

@app.route('/get_issue_numbers', methods=['POST'])
def get_issue_numbers():
    # 获取彩票的期号
    # 传入的信息包括：彩票类型（1:大乐透，2：双色球）
    lottery_type = request.get_json()['lottery_type']

    if lottery_type == "大乐透":
        lottery_type_int = 1
    else:
        lottery_type_int = 2

    # 根据彩票类型获取对应的期号数据
    with app.app_context():
        issues = Numbers.query.filter_by(type = lottery_type_int).order_by(Numbers.lotteryDrawNum.desc()).limit(10).all()

    issue_numbers= []
    for k in issues:
        # print(k.lotteryDrawNum)
        issue_numbers.append(k.lotteryDrawNum)

    return jsonify(issue_numbers)


@app.route('/check_winning_test', methods=['get'])
def check_winning_test():
    # 测试中奖函数用
    # 初始化结果
    results = []

    # 大乐透中奖号码
    win_number_lat = [{"qh": 23129, "numbers": [9, 23, 25, 27, 33, 6, 12], "win_level": 1},
                      {"qh": 23129, "numbers": [9, 23, 25, 27, 33, 6, 10], "win_level": 2},
                      {"qh": 23129, "numbers": [9, 23, 25, 27, 33, 9, 10], "win_level": 3},
                      {"qh": 23129, "numbers": [9, 23, 25, 27, 29, 6, 12], "win_level": 4},
                      {"qh": 23129, "numbers": [9, 23, 25, 27, 29, 6, 10], "win_level": 5},
                      {"qh": 23129, "numbers": [9, 23, 25, 28, 29, 6, 12], "win_level": 6},
                      {"qh": 23129, "numbers": [9, 23, 25, 27, 29, 7, 11], "win_level": 7},
                      {"qh": 23129, "numbers": [9, 23, 25, 26, 29, 6, 11], "win_level": 8},
                      {"qh": 23129, "numbers": [9, 23, 21, 24, 29, 6, 12], "win_level": 8},
                      {"qh": 23129, "numbers": [9, 20, 22, 26, 29, 6, 12], "win_level": 9},
                      {"qh": 23129, "numbers": [8, 17, 18, 20, 29, 6, 12], "win_level": 9},
                      {"qh": 23129, "numbers": [9, 23, 30, 31, 32, 6, 11], "win_level": 9},
                      {"qh": 23129, "numbers": [9, 23, 25, 26, 29, 9, 11], "win_level": 9}]

    # 双色球中奖号码
    win_number_dbs = [{"qh": 2023122, "numbers": [7 ,8 ,14 ,18 ,20 ,30 ,5], "win_level": 1},
                      {"qh": 2023122, "numbers": [7, 8, 14, 18, 20, 30, 7], "win_level": 2},
                      {"qh": 2023122, "numbers": [7, 8, 14, 18, 20, 23, 5], "win_level": 3},
                      {"qh": 2023122, "numbers": [7, 8, 14, 18, 20, 23, 7], "win_level": 4},
                      {"qh": 2023122, "numbers": [7, 8, 14, 18, 23, 25, 5], "win_level": 4},
                      {"qh": 2023122, "numbers": [7, 8, 14, 18, 23, 25, 7], "win_level": 5},
                      {"qh": 2023122, "numbers": [7, 8, 14, 15, 23, 25, 5], "win_level": 5},
                      {"qh": 2023122, "numbers": [7, 8, 13, 15, 23, 25, 5], "win_level": 6},
                      {"qh": 2023122, "numbers": [7, 9, 13, 15, 23, 25, 5], "win_level": 6},
                      {"qh": 2023122, "numbers": [3, 5, 13, 15, 23, 25, 5], "win_level": 6}]

    for l in win_number_lat:
        win_lev = is_winning(l['numbers'], 1, l['qh'])
        print(l['win_level'], win_lev)
        if l['win_level'] == win_lev['win']:
            tmp = "大乐透" + str(l['win_level']) + "---- OK"
        else:
            tmp = "大乐透" + str(l['win_level']) + "---- Fail"
        results.append(tmp)

    for k in win_number_dbs:
        win_lev = is_winning(k['numbers'], 2, k['qh'])
        if k['win_level'] == win_lev['win']:
            tmp = "双色球" + str(k['win_level']) + "---- OK"
        else:
            tmp = "双色球" + str(k['win_level']) + "---- Fail"
        results.append(tmp)

    return render_template('result.html', results=results, win_number="", draw_date="")

@app.route('/check_winning', methods=['POST'])
def check_winning():
    lottery_type_str = request.form['lottery_type']
    if lottery_type_str == "大乐透":
        lottery_type = 1
    else:
        lottery_type = 2
    issue_number = request.form['issue_number']
    input_numbers_str = request.form['numbers']

    # 将输入的字符串分割成彩票号码列表
    input_numbers_list = [num.strip() for num in input_numbers_str.split('\n')]

    # 初始化结果
    results = []

    # 遍历每组号码进行判断
    for input_numbers in input_numbers_list:
        input_numbers= input_numbers.split()
        # print(input_numbers)
        # 将列表中的所有元素转换为整型
        input_numbers_integer_list = [int(x) for x in input_numbers]
        print(input_numbers_integer_list)
        win = is_winning(input_numbers_integer_list, lottery_type, issue_number)
        if win['win']:
            result = "恭喜，" + ' '.join(input_numbers) + " 号码" + "中了「" + str(win['win']) + "」等奖！"
        else:
            result = "很遗憾，" + ' '.join(input_numbers) + " 号码未中奖。"
        results.append(result)
        win_numb = win["win_number"]
        win_date = win["draw_date"]

    return render_template('result.html', results=results, win_number=win_numb, draw_date=win_date)

def get_winner_data(type=1, span=20):
    # 从网络上获取中奖信息，参数：类型<1.大乐透；2.双色球>，查多少期<默认20>
    data = ""
    span = str(span)
    if type == 1:
        url = r"https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry?gameNo=85&provinceId=0&pageSize=" \
              + span + "&isVerify=1&pageNo=1&termLimits=" + span
    elif type == 2:
        url = r"http://www.cwl.gov.cn/cwl_admin/front/cwlkj/search/kjxx/findDrawNotice?name=ssq&issueCount=" + span + \
              "&issueStart=&issueEnd=&dayStart=&dayEnd=&pageNo=1&pageSize="+ span +"&week=&systemType=PC"
    else:
        return False
    response = requests.get(url)
    print(response.text)
    # 检查请求是否成功
    if response.status_code == 200:
        # 解析 JSON 响应
        json_data = response.json()

        # 返回 JSON 数据
        # return jsonify(json_data)
        return json_data
    else:
        return False


def get_result_data(type=2,file=None):
    # 获取中奖信息，支持文件读取，或者直接传数据进来做解释
    # type，读取类型：1:文件读取，2:JSON字符串解释
    if type == 1:
        with open(file, 'r', encoding='utf-8') as file:
            json_data = json.load(file)
    else:
        json_data = file

    result_data = {}
    # 大乐透和双色球的标识，1 大乐透； 2 双色球
    lottery_flag = 1
    try:
        # 大乐透数据提取
        value_data = json_data['value']
        for j in (value_data["list"]):
            # print(j)
            lotteryDrawNum = j["lotteryDrawNum"]  # 期号
            lotteryDrawResult = j["lotteryDrawResult"]  # 中奖结果
            DrawResult_list = lotteryDrawResult.split()
            lotteryDrawTime = j["lotteryDrawTime"]  # 开奖日期
            # print(lotteryDrawNum, lotteryDrawResult, lotteryDrawTime)
            # print(DrawResult_list[:5])
            # print(DrawResult_list[-2:])
            # print(lotteryDrawNum, ":", DrawResult_list)
            # 字典：{"期号": {"前区":xxx, "后区":xxx}
            result_data[lotteryDrawNum] = {"first": DrawResult_list[:5], "last": DrawResult_list[-2:], "draw_date":lotteryDrawTime}
    except:
        lottery_flag = 2

    if lottery_flag == 2:
        # 双色球数据提取
        value_data = json_data['result']
        for k in value_data:
            code = k["code"] # 期号
            red = k["red"] # 红色球
            red_list = red.split(",")
            blue = k["blue"] # 蓝色球
            lotteryDrawTime = k["date"]  # 开奖日期
            result_data[code] = {"first": red_list, "last": [blue], "draw_date":lotteryDrawTime}
    return {"value": result_data, "type" : lottery_flag}


def updata_db_insert_new_record(data=None):
    # 把中奖信息记录到数据库
    if not data:
        return None
    # 字段对应：
    """
    f_num = {"01": "f_01", "02":"f_02", "03":"f_03","04":"f_04","05":"f_05","06":"f_06","07":"f_07","08":"f_08","09":"f_09", \
             "10":"f_10","11":"f_11","12":"f_12","13":"f_13","14":"f_14","15":"f_15","16":"f_16","17":"f_17","18":"f_18","19":"f_19", \
             "20":"f_20","21":"f_21","22":"f_22","23":"f_23","24":"f_24","25":"f_25","26":"f_26","27":"f_27","28":"f_28","29":"f_29", \
             "30":"f_30","31":"f_31","32":"f_32","33":"f_33","34":"f_34","35":"f_35"}
    b_num = {"01": "b_01", "02":"b_02", "03":"b_03","04":"b_04","05":"b_05","06":"b_06","07":"b_07","08":"b_08","09":"b_09", \
             "10":"b_10","11":"b_11","12":"b_12","13":"b_13","14":"b_14","15":"b_15","16":"b_16"}
    """
    with app.app_context():
        for lot_num in data["value"]:
            # 前区
            tmp_f = []
            tmp_f = data["value"][lot_num]["first"]
            tmp_l = []
            tmp_l = data["value"][lot_num]["last"]
            type = data['type']
            datestr = data["value"][lot_num]["draw_date"]
            # 1 大乐透； 2 双色球
            if type == 2:
                new_record = Numbers(lotteryDrawNum = str(lot_num), draw_date = datestr, type = data['type'], f_1 = tmp_f[0], f_2 = tmp_f[1], \
                                     f_3 = tmp_f[2], f_4 = tmp_f[3], f_5 = tmp_f[4], f_6 = tmp_f[5], l_1 = tmp_l[0])
            else:
                new_record = Numbers(lotteryDrawNum=str(lot_num), draw_date = datestr, type=data['type'], f_1=tmp_f[0], f_2=tmp_f[1], \
                                     f_3=tmp_f[2], f_4=tmp_f[3], f_5=tmp_f[4], l_1=tmp_l[0], l_2=tmp_l[1])
            db.session.merge(new_record)
        # 提交更改到数据库
        db.session.commit()


# 定义一个定时任务，定时去更新中奖信息
@app.route('/update_win_info', methods=['GET'])
def update_win_info():
    data = {}
    try:
        for i in range(1,3):
            url_data = get_winner_data(i, 5)
            data = get_result_data(2, url_data)
            updata_db_insert_new_record(data)
        return render_template('result.html', results=["OK"], win_number="", draw_date="")
    except:
        return render_template('result.html', results=["Fail"], win_number="", draw_date="")

# 使用cron表达式来配置任务触发器
cron_trigger = CronTrigger(day_of_week='mon,tue,wed,thu,sat,sun', hour=22)
scheduler.add_job(update_win_info, trigger=cron_trigger)


if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(host='0.0.0.0',debug=True, port=8010)
